package com.erlang4j.internal.process;

import static com.erlang4j.api.Erlang4jMessageLanguage.atom;
import static com.erlang4j.api.Erlang4jMessageLanguage.binding;
import static com.erlang4j.api.Erlang4jMessageLanguage.state;
import static com.erlang4j.api.Erlang4jMessageLanguage.string;
import static com.erlang4j.api.Erlang4jMessageLanguage.tuple;
import junit.framework.TestCase;

import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpNode;
import com.erlang4j.api.exceptionHandler.SysoutExceptionHandler;
import com.erlang4j.internal.adapters.MockAdapter;
import com.erlang4j.internal.basicIo.MockBasicMailBox;
import com.erlang4j.tests.Erlang4JTestHelper;

public class StateMachineOneStateThreadTest extends TestCase {

	private OtpErlangPid self;
	private MockBasicMailBox mockBasicMailBox;
	private StateMachine process;
	private MockAdapter adapter1;
	private MockAdapter adapter2;
	private MockAdapter adapter3;

	public void testIsAlive() throws InterruptedException {
		assertFalse(process.isAlive());

		MessageProcessorThread thread = process.spawn();

		assertTrue(thread.isAlive()); // I know this is potential race condition...but this should always be true
		// because of the code in spawn, so if it EVER goes wrong its bad
		assertTrue(process.isAlive());

		while (adapter3.getCount() < 1)
			Thread.sleep(0);

		assertTrue(thread.isAlive());
		assertTrue(process.isAlive());

		thread.terminate();

		assertFalse(process.isAlive());
		assertFalse(thread.isAlive()); // I know this is potential race condition...but this should always be false
		// because of the code in terminate, so if it EVER goes wrong its bad
	}

	public void testAdaptersGotCalled() throws InterruptedException {
		MessageProcessorThread thread = process.spawn();
		while (adapter3.getCount() < 1)
			Thread.sleep(0);

		assertEquals(1, adapter1.getCount());
		assertEquals(1, adapter2.getCount());
		assertEquals(1, adapter3.getCount());

		assertEquals(binding("Initial", "initial", "Value", "value1"), adapter1.context);
		assertEquals(binding("Initial", "initial"), adapter2.context);
		assertEquals(binding("Initial", "initial"), adapter3.context);

		thread.terminate();
	}

	public void testWithNoAdapters() {
		process = new StateMachine(mockBasicMailBox, new SysoutExceptionHandler(), binding("Initial", "initial"));
		Erlang4JTestHelper.assertThrows(IllegalStateException.class, new Runnable() {
			public void run() {
				process.spawn();
			}
		});
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		self = new OtpNode("asd").createPid();
		mockBasicMailBox = new MockBasicMailBox(self, tuple(atom("one"), string("value1")), atom("two"), string("initial"));
		adapter1 = new MockAdapter("{one,Value}");
		adapter2 = new MockAdapter("two");
		adapter3 = new MockAdapter("Initial");
		process = new StateMachine(mockBasicMailBox, new SysoutExceptionHandler(), binding("Initial", "initial"), state(null, adapter1, adapter2, adapter3));
	}
}
